﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
using Shoozla.ViewModel;
using Shoozla.View;
using System.Threading;
using Shoozla.Helper;
using Shoozla.DataModel;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;


namespace Shoozla
{

    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : System.Windows.Application
    {
        #region Enums
        public enum AppStatus {
            Idle,
            ReadingFiles,
            SearchingCovers,
            ApplyingCovers
        }
        public enum ThreadingFactorEnum
        {
            Single,
            Medium,
            Maximum
        }
        public enum StartingMode
        { 
            Visual,
            Background
        }
        #endregion

        #region  properties

        private const String APPKEY = "a0c4fb8c72433dad6651a47c956266a3";
        private const String SECRET = "06c1629754f2401f1ac9604af35cdf4c";
        public  static  String LogFileName = "shoozlaCMD-log.txt";
        private static  String EventSourceName = "Shoozla";

        public static ICoverStorage CoverStorage;
        public static ICoverSearcher CoverSearcher;
        public static StatisticsLogger Logger;
        public static TxtTraceListener Tracer;       
        public static AppStatus CurrenAppStatus;
        public static ProgressBarView ProgressBarWindow;
        public static ThreadingFactorEnum ThreadingFactor = ThreadingFactorEnum.Maximum; //num of threads
        public static LASTFMService lastFMsrv;
        //views
        public static FolderListView FolderView;
        public static SummaryView SummaryView;
        public static PreviewView PreviewView;
        public static MainWindow MainView;
        
        #region thread workers

        private static ListWorker<Mp3File> _coverWorker;
        private static ListWorker<Mp3File> _searchWorker;
        private static ListWorker<FileInfo> _fileWorker;
        
       
        public static ListWorker<FileInfo> FileWorker
        {
            get { return _fileWorker; }
            set {
                if (value != null)
                {
                    _fileWorker = value;
                    _fileWorker.ListWorkerDone += new EventHandler(OnListWorkerDone);
                }
            }
        }
        public static ListWorker<Mp3File> SearchWorker
        {
            get { return _searchWorker; }
            set
            {
                if (value != null)
                {
                    _searchWorker = value;
                    _searchWorker.ListWorkerDone += new EventHandler(OnListWorkerDone);
                }
            }
        }
        public static ListWorker<Mp3File> CoverWorker
        {
            get { return _coverWorker; }
            set
            {
                if (value != null)
                {
                    _coverWorker = value;
                    _coverWorker.ListWorkerDone += new EventHandler(OnListWorkerDone);
                }
            }
        }

        static void OnListWorkerDone(object sender, EventArgs e)
        {
            //cancel all 
            App.StopWorkingThreads();

            ((PreviewViewModel)PreviewView.DataContext).AllItems = CoverStorage.GetAllCovers();
            
           // App.CurrenAppStatus = AppStatus.Idle;
        }

        #endregion

        #endregion

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            Tracer = new TxtTraceListener(App.LogFileName);
            CurrenAppStatus = AppStatus.Idle;
            Logger = new StatisticsLogger();
            lastFMsrv = LASTFMService.GetInstance(App.APPKEY, App.SECRET);
            CoverStorage = new MemoryCoverStorage();

            Thread.Sleep(500); //splash screen

            //single-instance application
            bool mutexIsNew;
            using (Mutex m = new Mutex(true, "Shoozla", out mutexIsNew))
            {
                if (mutexIsNew)
                {
                    //first instance
                    switch (CheckStartingMode())
                    {
                        case StartingMode.Visual: { StartUI(); break; }
                        case StartingMode.Background: { StartBackground();  break; }
                    }
                }
                else
                {
                    //another instance running
                    System.Windows.MessageBox.Show("another Instance of Shoozla is running.", "Shoozla", MessageBoxButton.OK, MessageBoxImage.Stop);
                    Thread.Sleep(1500); //splash screen
                }
            }

            Tracer.Save();
            System.Windows.Application.Current.Shutdown();
            
        }

        public static StartingMode CheckStartingMode()
        {
           //no parameters --> VISUAL

           String[] pars = System.Environment.GetCommandLineArgs();
           if (pars.Length <= 1)
               return StartingMode.Visual; //first par is always the file name
           else
               return StartingMode.Background;
        }

        public static void StartUI()
        {
            MainView = new MainWindow();
            FolderView = new FolderListView();
            PreviewView = new PreviewView();
            //SummaryView = new SummaryView();

            var viewModel = new MainWindowViewModel();

            // Allow all controls in the window to 
            // bind to the ViewModel by setting the 
            // DataContext, which propagates down 
            // the element tree.
            MainView.DataContext = viewModel;

            try
            {
                MainView.ShowDialog();
            }
            catch (Exception ex)
            {
                App.LogEntry("[ERROR]: App: Generic Error: " + ex.Message);
                //TaskDialogClass.TaskDialog(
                //      new System.Windows.Interop.WindowInteropHelper((Window)App.MainView).Handle,
                //      IntPtr.Zero, "Shoozla","Generic Error", "Check internet connection\n " + ex.Message, 
                //      TaskDialogButtons.OK,
                //      TaskDialogIcon.SecurityError
                //       );
                System.Windows.MessageBox.Show("Check internet connection\n " + ex.Message, "Generic Error", MessageBoxButton.OK);
            }

        }

        public static void StartBackground()
        {
            //i.e: command line or scheduled task
            //parameters:
            // folder - path of the folder to check

            String[] pars = System.Environment.GetCommandLineArgs();
            
            if (pars.Length != 2)
                ShowUsage();

            DirectoryInfo folder = GetFolderName(pars);
            if (folder == null)
                return;
            try
            {
                if (!EventLog.SourceExists(EventSourceName))
                    EventLog.CreateEventSource(EventSourceName, "Application");
                LogEvent("Shoozla started on " + folder.FullName, false, 1);
            }
            catch (InvalidOperationException invalidOp)
            {
                LogEntry("[ERROR] StartBackground: Cannot create event source");
            }
            catch (Exception e)
            {
                LogEntry("[ERROR] StartBackground: " + e.Message);
            }
            finally
            {
                BatchSearch.StartBatchSearch(folder);
            }
        }

        private static DirectoryInfo GetFolderName(string[] args)
        {
            string folderName = args[1];

            if (!Directory.Exists(folderName))
            {
                LogEntry(string.Format("Folder: \"{0}\" not found.", folderName));
                return null;
            }

            return new DirectoryInfo(folderName);
        }

        private static void ShowUsage()
        {
            LogEntry("usage: shoozla FolderName");
        }

        public static void LogEntry(string message)
        {
            //Console.WriteLine(message + Environment.NewLine);
            Trace.WriteLine(message);
        }

        public static void LogEvent(string message, bool isError, int ID)
        {
            EventLog.WriteEntry(EventSourceName, message, isError?EventLogEntryType.Error:EventLogEntryType.Information, ID);
        }
       
        public static void StopWorkingThreads()
        {         
            switch (App.CurrenAppStatus)
            {
                case App.AppStatus.ApplyingCovers: { if (App.CoverWorker != null) App.CoverWorker.StopThreads(); break; }
                case App.AppStatus.SearchingCovers: { if (App.SearchWorker != null) App.SearchWorker.StopThreads(); break; }
                case App.AppStatus.ReadingFiles: { if (App.FileWorker != null) App.FileWorker.StopThreads(); break; }
                default:
                    {
                        if (App.CoverWorker != null) App.CoverWorker.StopThreads();
                        if (App.SearchWorker != null) App.SearchWorker.StopThreads();
                        if (App.FileWorker != null) App.FileWorker.StopThreads();
                        break;
                    }
            }

            App.MainView.Dispatcher.Invoke((Action)(() =>
            {
                App.MainView.StopProgressBar();
                ((MainWindowViewModel)App.MainView.DataContext).ShowNextWindow();
            }));
            App.CurrenAppStatus = App.AppStatus.Idle;
        }

        public static int CalculateTreads(int itemsCount)
        {
            switch (App.ThreadingFactor)
            {
                case ThreadingFactorEnum.Single: {

                    System.Management.ManagementObject mo = new System.Management.ManagementObject("Win32_ComputerSystem.Name=\"" + Environment.MachineName + "\"");
                    return Int32.Parse(mo["NumberOfLogicalProcessors"].ToString());
                }
                case ThreadingFactorEnum.Medium :{
                        int n = (itemsCount / 4);
                        if(n <= 0) return 1;
                        else
                            return n;
                    };
                case ThreadingFactorEnum.Maximum : {return itemsCount;}
                default : {return 10;}
            }
        }

        
    }
}
